#include "stdafx.h"
#include "Thread.hpp"

HpsFramework::Threading::Thread::SignalType HpsFramework::Threading::Thread::wait( DWORD ms /*= INFINITE */ )
{
	HANDLE handles[2] = { this->_serviceEvent.getEvent(), this->_exitEvent.getEvent() };
	DWORD waitResult = WaitForMultipleObjects(2, handles, FALSE, ms );
	if ( waitResult == WAIT_TIMEOUT )
	{
		return SignalTimeout;
	}
	return (waitResult == WAIT_OBJECT_0) ? ServiceSignal : ExitSignal;
}

bool HpsFramework::Threading::Thread::waitForExit( DWORD ms /*= INFINITE */ )
{
	DWORD waitResult = WaitForSingleObject ( this->_exitEvent.getEvent(), ms );
	if ( waitResult == WAIT_TIMEOUT )
	{
		return false;
	}
	return true;
}

bool HpsFramework::Threading::Thread::waitForService( DWORD ms /*= INFINITE */ )
{
	DWORD waitResult = WaitForSingleObject ( this->_serviceEvent.getEvent(), ms );
	if ( waitResult == WAIT_OBJECT_0 || waitResult == WAIT_TIMEOUT )
	{
		return false;
	}
	return true;
}

HpsFramework::Threading::Thread::Thread() : _threadId(0), _threadHandle(NULL)
{

}

HpsFramework::Threading::Thread::~Thread()
{
	this->stop();
}

bool HpsFramework::Threading::Thread::start( int processorId /*= -1*/ )
{
	if(!this->_threadHandle)
	{
		this->_cleanupEvent.reset();
		this->_threadHandle = (HANDLE)_beginthreadex(NULL, NULL, Thread::executionHandler, this, 1, &this->_threadId);
		if(this->_threadHandle && processorId != -1)
		{
			SetThreadAffinityMask ( this->_threadHandle, 1 << processorId );
		}
	}
	return (this->_threadHandle != 0);
}

void HpsFramework::Threading::Thread::stop( bool waitcleanup /*= true */ )
{
	if(this->_threadHandle)
	{
		this->_exitEvent.set();
		if(waitcleanup)
		{
			this->_cleanupEvent.wait();
		}
	}
}

void HpsFramework::Threading::Thread::signal()
{
	this->_serviceEvent.set();
	this->_serviceEvent.reset();
}

bool HpsFramework::Threading::Thread::alive()
{
	return (this->_threadHandle != 0);
}

bool HpsFramework::Threading::Thread::exiting()
{
	if ( WaitForSingleObject(this->_exitEvent.getEvent(), 0) == WAIT_OBJECT_0 )
	{
		return true;
	}
	return false;
}

unsigned int __stdcall HpsFramework::Threading::Thread::executionHandler( void* param )
{
	int ret = -1;
	Thread* thread = (Thread*) param;
	if(thread)
	{
		ret = thread->run();
		CloseHandle(thread->_threadHandle);
		thread->_threadHandle = NULL;
		thread->_cleanupEvent.set();
	}
	return ret;
}
